💡 核心思想
const 是 C++ 中威力最强大的工具之一。它允许你指定一个语义约束(即“改对象不该被改动”),而编译器会强制实施这项约束。它不仅能防止意外修改,还能帮助编译器进行优化。
🔑 关键点详解
1. 指针与 const (Pointers)
这是最基础也最容易混淆的部分。规则看 * 号的位置:
- const 在
*左边:被指物是常量 (Data is const)。 - const 在
*右边:指针本身是常量 (Pointer is const)。 - 两边都有:数据和指针都是常量。
cpp
char greeting[] = "Hello";
char* p = greeting; // non-const pointer, non-const data
const char* p = greeting; // non-const pointer, const data
char* const p = greeting; // const pointer, non-const data
const char* const p = greeting; // const pointer, const dataSTL 迭代器补充:
std::vector<int>::iterator相当于T*。std::vector<int>::const_iterator相当于const T*(推荐使用)。
2. 函数声明中的 const
在一个函数声明式内,const 可以和函数返回值、各参数、函数自身(如果是成员函数)产生关联。
- const 参数:防止函数内部意外修改参数(尽量传
const reference)。 - const 返回值:防止用户对返回值进行荒谬的操作。
- 例如:
const Rational operator*(...)可以防止(a * b) = c这种错误赋值。
- 例如:
3. const 成员函数 (Member Functions)
这是 const 最具威力的应用场景。
- 目的:确认该成员函数可作用于 const 对象。
- 重载:两个成员函数如果只是常量性 (constness) 不同,可以被重载。
cpp
class TextBlock {
public:
// const 版本:用于 const 对象
const char& operator[](std::size_t position) const { return text[position]; }
// non-const 版本:用于 non-const 对象
char& operator[](std::size_t position) { return text[position]; }
private:
std::string text;
};4. 逻辑常量性 (Logical Constness) vs 二进制常量性 (Bitwise Constness)
- 二进制常量性:C++ 编译器的默认定义。只要不修改对象内的任何成员变量(bit),就是 const。
- 逻辑常量性:一个 const 成员函数可以修改它所处理的对象内的某些 bits,但只有在客户端侦测不出的情况下才得如此。
问题:如果我想在 const 函数里修改一个缓存变量(如 lengthIsValid),编译器会报错。 解法:使用 mutable 关键字。
cpp
class CTextBlock {
private:
char* pText;
mutable std::size_t textLength; // 即使在 const 函数中也可以被修改
mutable bool lengthIsValid;
public:
std::size_t length() const {
if (!lengthIsValid) {
textLength = std::strlen(pText); // 合法,因为是 mutable
lengthIsValid = true;
}
return textLength;
}
};5. 在 const 和 non-const 成员函数中避免重复
当 const 和 non-const 版本的实现完全一样时,为了避免代码重复,可以让 non-const 版本调用 const 版本(反之则不行)。 这需要两次转型:
static_cast:把*this转为const。const_cast:把返回值的const移除。
cpp
class TextBlock {
public:
const char& operator[](std::size_t position) const {
// ... 边界检查 ...
// ... 志记访问 ...
return text[position];
}
char& operator[](std::size_t position) {
return const_cast<char&>( // 2. 移除 const
static_cast<const TextBlock&>(*this) // 1. 为 *this 加上 const
[position] // 调用 const 版本
);
}
};🚀 总结 (Takeaway)
- 将某些东西声明为 const 可帮助编译器侦测出错误用法。 const 可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。
- 编译器强制实施 bitwise constness,但你编写程序时应该使用“概念上的常量性” (logical constness)。 (善用
mutable) - 当 const 和 non-const 成员函数有着实质等价的实现时,令 non-const 版本调用 const 版本可避免代码重复。
